package stream.MultiThread;

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.*;

import static java.util.stream.Collectors.toList;

/**
 * CompletableFuture异步编程
 * Created by Robo on 2017/9/30.
 */
public class CompletableFutureTest {

    public static void main(String[] args) {
//        java5Future();
        System.out.println("恭喜发财.");
        paralleStreamAndCompletableFurture();
    }

    public static void java5Future(){
        //创建ExecutorService，并且通过它向线程池提交任务
        ExecutorService executorService = Executors.newCachedThreadPool();
        //向线程池提交任务
        Future future =  executorService.submit(new Callable<Double>() {
            @Override
            public Double call() throws Exception {
                return doSomeLongTime();
            }
        });

        //当前线程继续做其他事情
        doSomeElse();
        //获取异步操作的结果
        try {
            double result = 0.0;
            result = (double)future.get(1, TimeUnit.SECONDS);//这里如果异步请求结果还没返回会报错
            System.out.println(result);

        } catch (InterruptedException e) {
            //线程被中断
            e.printStackTrace();
        } catch (ExecutionException e) {
            //线程抛出异常
            e.printStackTrace();
        } catch (TimeoutException e) {
            //线程超时
            e.printStackTrace();
        }
    }

    public static double doSomeLongTime(){
        double sum = 0;
        double max = 99999.99;
        for(double i =0; i< 1; ){
            sum += i;
            i += 0.1;
        }
        /*try {
            Thread.sleep(2000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }*/
        return sum;
    }

    public static void doSomeElse(){
        try {
            Thread.sleep(2000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    //////////////////parallelStream的并行操作：

    public static void paralleStreamAndCompletableFurture(){
        long start = System.currentTimeMillis();
        System.out.println(findPrice("java8实战"));
        long duration = System.currentTimeMillis() - start;
        System.out.println("总消耗时间：" + duration + "毫秒");

        start = System.currentTimeMillis();
        System.out.println(findPrice2("java8实战"));
        duration = System.currentTimeMillis() - start;
        System.out.println("总消耗时间：" + duration + "毫秒");

        start = System.currentTimeMillis();
        System.out.println(findPrice3("java8实战"));
        duration = System.currentTimeMillis() - start;
        System.out.println("总消耗时间：" + duration + "毫秒");

        start = System.currentTimeMillis();
        System.out.println(findPrice4("java8实战"));
        duration = System.currentTimeMillis() - start;
        System.out.println("总消耗时间：" + duration + "毫秒");
    }
    private static List<Shop> shops = Arrays.asList(
            new Shop("苏宁"),
            new Shop("国美"),
            new Shop("京东商城"),
            new Shop("天猫商城"));

    public static List<String> findPrice(String product){
        return shops.parallelStream()
                .map(shop -> String.format("%s 的价格是 %.2f", shop.getName(), shop.getPrice(product)))
                .collect(toList());
    }

    ////////////////////CompletableFuture的并行操作
    public static List<String> findPrice2(String product){
        List<CompletableFuture<String>> priceFuture = shops.stream()
                .map(shop -> CompletableFuture.supplyAsync( // 使用异步的方式计算每种商品的价格
                        () -> String.format("%s 的价格是 %.2f", shop.getName(), shop.getPrice(product))))
                .collect(toList());

        return priceFuture.stream().map(CompletableFuture::join) //join 操作等待所有异步操作的结果
                .collect(toList());
    }

///////////////////////////////////同步调用
    public static List<String> findPrice3(String product){
        return shops.stream()
                .map(shop -> shop.getPrice2(product)) //获取原始报价
                .map(Quote::parse) //解析报价字符串
                .map(Discount::applyDiscount) //调用折扣服务应用报价折扣
                .collect(toList());
    }

    /////////////////////////////////使用CompletableFutures异步操作
    public static List<String> findPrice4(String product){
        ExecutorService executorService = Executors.newCachedThreadPool();
        List<CompletableFuture<String>> priceFuture = shops.stream()
                .map(shop -> CompletableFuture.supplyAsync( // 异步获取价格
                        () -> shop.getPrice2(product), executorService))
                .map(future -> future.thenApply(Quote::parse)) // 获取到价格后对价格解析
                .map(future -> future.thenCompose(quote -> CompletableFuture.supplyAsync( // 另一个异步任务构造异步应用报价
                        () -> Discount.applyDiscount(quote), executorService)))
                .collect(toList());
        return priceFuture.stream()
                .map(CompletableFuture::join) //join 操作和get操作有相同的含义，等待所有异步操作的结果。
                .collect(toList());
    }
}
